package com.wish.nettywithpack;

import com.wish.common.MyUtils;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;


/**
 * @author tantexian
 * @since 2016/7/11
 */
public class NettyRobotServerWithPack {

    public static void main(String[] args) {
        final int port = args.length >= 1 ? Integer.parseInt(args[0]) : MyUtils.getDefaultPort();
        try {
            new NettyRobotServerWithPack().bind(port);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void bind(int port) throws InterruptedException {
        // 创建NIO线程组（Reactor封装），用于处理网络事件
        // 处理客户端连接NIO线程组
        NioEventLoopGroup accetpNioEventLoopGroup = new NioEventLoopGroup();
        // 处理网络IO事件NIO线程组
        NioEventLoopGroup handleNioEventLoopGroup = new NioEventLoopGroup();

        try {
            // NIO服务启动辅助类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(accetpNioEventLoopGroup, handleNioEventLoopGroup)// 将线程组传递到group中
                    .channel(NioServerSocketChannel.class)// 类似java nio中ServerSocketChannel
                    .option(ChannelOption.SO_BACKLOG, 1024)// 设置TCP参数
                    //        .childHandler(new MyChannelHandler());// 绑定IO事件处理类，类似java nio中的handler，主要用来处理网络IO事件
                    .childHandler(new DelimiterChannelHandler()); // 使用自定义分隔符，拆包粘包

            // 绑定端口，然后调用同步阻塞方法
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            System.out.println("I,m a smart netty simple robot and wait for you ask. [I'm listen on port " + port + "]\n");
            // 等待链路关闭之后，才退出main函数
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 优雅关闭退出
            accetpNioEventLoopGroup.shutdownGracefully();
            handleNioEventLoopGroup.shutdownGracefully();
        }

    }

    /**
     * IO事件处理类，类似java nio中的handler，主要用来处理网络IO事件
     *
     * @author tantexian
     * @since 2016/7/12
     * @params
     */
    class MyChannelHandler extends ChannelInitializer {
        protected void initChannel(Channel channel) throws Exception {
            // Netty中，可以注册多个handler。ChannelInboundHandler按照注册的先后顺序执行；ChannelOutboundHandler按照注册的先后顺序逆序执行
            // LineBasedFrameDecoder+StringDecoder,组合就是按行切换的文本解析器，用来支持TCP的粘包和拆包
            channel.pipeline().addLast(new LineBasedFrameDecoder(1024)); // 以换行符(\n or \r\n)为结束标志的解码器
            channel.pipeline().addLast(new StringDecoder()); // 自动将接受到的对象转换为String
            channel.pipeline().addLast(new LineBasedAndStringServerHandle());

            // 如果是自动长度TCP的粘包和拆包
            //channel.pipeline().addLast(new FixedLengthFrameDecoder(20));


        }
    }

    class DelimiterChannelHandler extends ChannelInitializer {
        protected void initChannel(Channel channel) throws Exception {
            // 自定义分隔符解析器，以$_作为分隔
            ByteBuf delimiter = Unpooled.copiedBuffer("$_END_$".getBytes());
            channel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
            channel.pipeline().addLast(new StringDecoder()); // 自动将接受到的对象转换为String
            channel.pipeline().addLast(new StringEncoder()); // 编码
            channel.pipeline().addLast(new DelimiterAndStringServerHandle());
        }
    }

}
